home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 039a / jpsrc2.zip / EGETOPT.C < prev    next >
C/C++ Source or Header  |  1991-12-03  |  8KB  |  287 lines

  1. /*
  2.  * egetopt.c -- Extended 'getopt'.
  3.  *
  4.  * A while back, a public-domain version of getopt() was posted to the
  5.  * net.  A bit later, a gentleman by the name of Keith Bostic made some
  6.  * enhancements and reposted it.
  7.  *
  8.  * In recent weeks (i.e., early-to-mid 1988) there's been some
  9.  * heated discussion in comp.lang.c about the merits and drawbacks
  10.  * of getopt(), especially with regard to its handling of '?'.
  11.  *
  12.  * In light of this, I have taken Mr. Bostic's public-domain getopt()
  13.  * and have made some changes that I hope will be considered to be
  14.  * improvements.  I call this routine 'egetopt' ("Extended getopt").
  15.  * The default behavior of this routine is the same as that of getopt(),
  16.  * but it has some optional features that make it more useful.  These
  17.  * options are controlled by the settings of some global variables.
  18.  * By not setting any of these extra global variables, you will have
  19.  * the same functionality as getopt(), which should satisfy those
  20.  * purists who believe getopt() is perfect and can never be improved.
  21.  * If, on the other hand, you are someone who isn't satisfied with the
  22.  * status quo, egetopt() may very well give you the added capabilities
  23.  * you want.
  24.  *
  25.  * Look at the enclosed README file for a description of egetopt()'s
  26.  * new features.
  27.  *
  28.  * The code was originally posted to the net as getopt.c by ...
  29.  *
  30.  *    Keith Bostic
  31.  *    ARPA: keith@seismo 
  32.  *    UUCP: seismo!keith
  33.  *
  34.  * Current version: added enhancements and comments, reformatted code.
  35.  *
  36.  *    Lloyd Zusman
  37.  *    Master Byte Software
  38.  *    Los Gatos, California
  39.  *    Internet:    ljz@fx.com
  40.  *    UUCP:        ...!ames!fxgrp!ljz
  41.  *
  42.  *        May, 1988
  43.  *
  44.  * Modified for use in free JPEG code:
  45.  *
  46.  *    Ed Hanway
  47.  *    UUCP:    uunet!sisd!jeh
  48.  *
  49.  *    October, 1991
  50.  */
  51.  
  52. /* The original egetopt.c was written not to need stdio.h.
  53.  * For the JPEG code this is an unnecessary and unportable assumption.
  54.  * Also, we make all the variables and routines "static" to avoid
  55.  * possible conflicts with a system-library version of getopt.
  56.  *
  57.  * In the JPEG code, this file is compiled by #including it in jcmain.c
  58.  * or jdmain.c.  Since ANSI2KNR does not process include files, we can't
  59.  * rely on it to convert function definitions to K&R style.  Hence we
  60.  * provide both styles of function header with an explicit #ifdef PROTO (ick).
  61.  */
  62.  
  63. #define GVAR static        /* make empty to export these variables */
  64.  
  65. /*
  66.  * None of these constants are referenced in the executable portion of
  67.  * the code ... their sole purpose is to initialize global variables.
  68.  */
  69. #define BADCH        (int)'?'
  70. #define NEEDSEP        (int)':'
  71. #define MAYBESEP    (int)'\0'
  72. #define EMSG        ""
  73. #define START        "-"
  74.  
  75. /*
  76.  * Here are all the pertinent global variables.
  77.  */
  78. GVAR int opterr = 1;        /* if true, output error message */
  79. GVAR int optind = 1;        /* index into parent argv vector */
  80. GVAR int optopt;        /* character checked for validity */
  81. GVAR int optbad = BADCH;    /* character returned on error */
  82. GVAR int optchar = 0;        /* character that begins returned option */
  83. GVAR int optneed = NEEDSEP;    /* flag for mandatory argument */
  84. GVAR int optmaybe = MAYBESEP;    /* flag for optional argument */
  85. GVAR const char *optarg;    /* argument associated with option */
  86. GVAR const char *optstart = START; /* list of characters that start options */
  87.  
  88.  
  89. /*
  90.  * Macros.
  91.  */
  92.  
  93. /*
  94.  * Conditionally print out an error message and return (depends on the
  95.  * setting of 'opterr').
  96.  */
  97. #define TELL(S)    { \
  98.     if (opterr) \
  99.         fprintf(stderr, "%s%s%c\n", *nargv, (S), optopt); \
  100.     return (optbad); \
  101. }
  102.  
  103. /*
  104.  * This works similarly to index() and strchr().  I include it so that you
  105.  * don't need to be concerned as to which one your system has.
  106.  */
  107.  
  108. #ifdef PROTO
  109. LOCAL const char *
  110. _sindex (const char *string, int ch)
  111. #else
  112. LOCAL const char *
  113. _sindex (string, ch)
  114.      const char *string;
  115.      int ch;
  116. #endif
  117. {
  118.     if (string != NULL) {
  119.         for (; *string != '\0'; ++string) {
  120.             if (*string == (char)ch) {
  121.                 return (string);
  122.             }
  123.         }
  124.     }
  125.  
  126.     return (NULL);
  127. }
  128.  
  129. /*
  130.  * Here it is:
  131.  */
  132.  
  133. #ifdef PROTO
  134. LOCAL int
  135. egetopt (int nargc, char **nargv, const char *ostr)
  136. #else
  137. LOCAL int
  138. egetopt (nargc, nargv, ostr)
  139.      int nargc;
  140.      char **nargv;
  141.      const char *ostr;
  142. #endif
  143. {
  144.     static const char *place = EMSG; /* option letter processing */
  145.     register const char *oli;     /* option letter list index */
  146.     register const char *osi = NULL; /* option start list index */
  147.  
  148.     if (nargv == (char **)NULL) {
  149.         return (EOF);
  150.     }
  151.  
  152.     if (nargc <= optind || nargv[optind] == NULL) {
  153.         return (EOF);
  154.     }
  155.  
  156.     if (place == NULL) {
  157.         place = EMSG;
  158.     }
  159.  
  160.     /*
  161.      * Update scanning pointer.
  162.      */
  163.     if (*place == '\0') {
  164.         place = nargv[optind];
  165.         if (place == NULL) {
  166.             return (EOF);
  167.         }
  168.         osi = _sindex(optstart, *place);
  169.         if (osi != NULL) {
  170.             optchar = (int)*osi;
  171.         }
  172.         if (optind >= nargc || osi == NULL || *++place == '\0') {
  173.                 return (EOF);
  174.         }
  175.  
  176.         /*
  177.          * Two adjacent, identical flag characters were found.
  178.          * This takes care of "--", for example.
  179.          */
  180.         if (*place == place[-1]) {
  181.             ++optind;
  182.             return (EOF);
  183.         }
  184.     }
  185.  
  186.     /*
  187.      * If the option is a separator or the option isn't in the list,
  188.      * we've got an error.
  189.      */
  190.     optopt = (int)*place++;
  191.     oli = _sindex(ostr, optopt);
  192.     if (optopt == optneed || optopt == optmaybe || oli == NULL) {
  193.         /*
  194.          * If we're at the end of the current argument, bump the
  195.          * argument index.
  196.          */
  197.         if (*place == '\0') {
  198.             ++optind;
  199.         }
  200.         TELL(": illegal option -- ");    /* byebye */
  201.     }
  202.  
  203.     /*
  204.      * If there is no argument indicator, then we don't even try to
  205.      * return an argument.
  206.      */
  207.     ++oli;
  208.     if (*oli == '\0' || (*oli != optneed && *oli != optmaybe)) {
  209.         /*
  210.          * If we're at the end of the current argument, bump the
  211.          * argument index.
  212.          */
  213.         if (*place == '\0') {
  214.             ++optind;
  215.         }
  216.         optarg = NULL;
  217.     }
  218.     /*
  219.      * If we're here, there's an argument indicator.  It's handled
  220.      * differently depending on whether it's a mandatory or an
  221.      * optional argument.
  222.      */
  223.     else {
  224.         /*
  225.          * If there's no white space, use the rest of the
  226.          * string as the argument.  In this case, it doesn't
  227.          * matter if the argument is mandatory or optional.
  228.          */
  229.         if (*place != '\0') {
  230.             optarg = place;
  231.         }
  232.         /*
  233.          * If we're here, there's whitespace after the option.
  234.          *
  235.          * Is it a mandatory argument?  If so, return the
  236.          * next command-line argument if there is one.
  237.          */
  238.         else if (*oli == optneed) {
  239.             /*
  240.              * If we're at the end of the argument list, there
  241.              * isn't an argument and hence we have an error.
  242.              * Otherwise, make 'optarg' point to the argument.
  243.              */
  244.             if (nargc <= ++optind) {
  245.                 place = EMSG;
  246.                 TELL(": option requires an argument -- ");
  247.             }
  248.             else {
  249.                 optarg = nargv[optind];
  250.             }
  251.         }
  252.         /*
  253.          * If we're here it must have been an optional argument.
  254.          */
  255.         else {
  256.             if (nargc <= ++optind) {
  257.                 place = EMSG;
  258.                 optarg = NULL;
  259.             }
  260.             else {
  261.                 optarg = nargv[optind];
  262.                 if (optarg == NULL) {
  263.                     place = EMSG;
  264.                 }
  265.                 /*
  266.                  * If the next item begins with a flag
  267.                  * character, we treat it like a new
  268.                  * argument.  This is accomplished by
  269.                  * decrementing 'optind' and returning
  270.                  * a null argument.
  271.                  */
  272.                 else if (_sindex(optstart, *optarg) != NULL) {
  273.                     --optind;
  274.                     optarg = NULL;
  275.                 }
  276.             }
  277.         }
  278.         place = EMSG;
  279.         ++optind;
  280.     }
  281.  
  282.     /*
  283.      * Return option letter.
  284.      */
  285.     return (optopt);
  286. }
  287.